package mint.modules.generator;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import org.antlr.runtime.tree.Tree;

import mint.MintLexer;
import mint.modules.generator.expression.ExprNode;
import mint.modules.generator.expression.Expression;
import mint.modules.generator.expression.ExpressionType;
import mint.modules.type.Type;

public class IfThenStmtNode extends Scope implements MintNode {
	private Expression expr;
	private BlockNode block;
	private int line;
	private List<String> errors;
	private List<Expression> ifelseExpressions;
	private List<BlockNode> blockNodes;	
	private BlockNode elseBlock;

	public IfThenStmtNode(Scope theParent, Tree ifStmtTree) {
		super(theParent, theParent.containerClass);
		expr = new ExprNode(theParent, ExpressionType.Right, ifStmtTree.getChild(0));
		block = new BlockNode(theParent, ifStmtTree.getChild(1));
		line = ifStmtTree.getLine();
		errors = new ArrayList<String>();
		ifelseExpressions = new ArrayList<Expression>();
		blockNodes = new ArrayList<BlockNode>();
		for (int i = 2; i < ifStmtTree.getChildCount(); i++)
		{
			Tree child = ifStmtTree.getChild(i);
			
			if( child.getType() == MintLexer.ELSEIF)
			{
				ifelseExpressions.add(new ExprNode(theParent, ExpressionType.Right, child.getChild(0)));
				blockNodes.add(new BlockNode(theParent, child.getChild(1)));
			} else if( child.getType() == MintLexer.ELSE)
			{
				elseBlock = new BlockNode(theParent, child.getChild(0));
			}
		}
	}

	@Override
	public void testSemantic() {
		expr.testSemantic();
		if (!expr.getType().equals(Type.booleanType))
			errors.add(line + ": expression in if statement must be boolean");
		block.testSemantic();
		
		for(Expression ifElseExpr : ifelseExpressions)
		{
			ifElseExpr.testSemantic();
			if (!ifElseExpr.getType().equals(Type.booleanType))
				errors.add(ifElseExpr.getLine() + ": expression in if-else statement must be boolean");
		}
		
		for (BlockNode ifElseBlock : blockNodes)
			ifElseBlock.testSemantic();
		
		if (elseBlock != null)
		{
			elseBlock.testSemantic();
		}
	}

	@Override
	public List<String> getSemanticErrors() {
		errors.addAll(expr.getSemanticErrors());
		errors.addAll(block.getSemanticErrors());
		for(Expression ifElseExpr : ifelseExpressions)
		{
			errors.addAll(ifElseExpr.getSemanticErrors());			
		}
		
		for (BlockNode ifElseBlock : blockNodes)
			errors.addAll(ifElseBlock.getSemanticErrors());
		
		if (elseBlock != null)
			errors.addAll(elseBlock.getSemanticErrors());
		return errors;
	}

	@Override
	public void emit(Formatter output) {
		String label1 = CounterManager.getInstance().generate("if");
		String label2 = CounterManager.getInstance().generate("if");
				
		expr.emit(output);
		output.format("ifeq %s\n", label1);
		block.emit(output);
		output.format("goto %s\n", label2);
		output.format("%s:\n", label1);
		
		for (int i = 0; i < ifelseExpressions.size(); i++)
		{
			String label = CounterManager.getInstance().generate("elseif");
			
			ifelseExpressions.get(i).emit(output);
			output.format("ifeq %s\n", label);
			blockNodes.get(i).emit(output);
			output.format("goto %s\n", label2);
			output.format("%s:\n", label);
		}
		if (elseBlock != null)
			elseBlock.emit(output);
		output.format("%s:\n", label2);
	}

	@Override
	public int getLine() {
		return line;
	}
	
	@Override
	public void printSymbolTable(Formatter output, int tabSize) {
		for (int i = 1; i <= tabSize; i++)
			output.format("\t");
		output.format("if:\n");
		block.printSymbolTable(output, tabSize + 1);
	}

}
